/*-
 * Copyright (C) 2018-2020, Shanghai Trusted Industry Control Platform Co., Ltd.
 * Created by 周正辉 (Zhenghui Zhou) <zhouzhenghui@ticpsh.com>, 赵楷文 (Kaiwen
 * Zhao) <zhaokaiwen@ticpsh.com>
 */

#ifndef TYPEGENERATOR_H
#define TYPEGENERATOR_H

#include <clang/AST/ASTContext.h>
#include <clang/AST/Decl.h>
#include <clang/AST/Type.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Sema/Sema.h>

#include <stdexcept>
#include <vector>

namespace rocket {
namespace incparser {

/**
 * @brief User Defined/Decled stmt parser
 */
class UDParser {
 public:
  class IllegalTypeParseException : public std::runtime_error {
   public:
    IllegalTypeParseException(std::string str) : std::runtime_error(str) {}
  };

 private:
  clang::CompilerInstance *CI;
  clang::FunctionTemplateDecl *FTD = nullptr;

  std::vector<IllegalTypeParseException> exceptions;

 public:
  UDParser(clang::CompilerInstance *_CI);

 public:
  const clang::ASTContext &getASTContext() const { return CI->getASTContext(); }
  const std::string flushASTContext() const;
  const std::vector<IllegalTypeParseException> &getRuntimeExceptions() const {
    return exceptions;
  }
  void cleanExceptions() { exceptions.clear(); }

 public:
  struct UDTemplateArg;
  using TAList = std::vector<std::shared_ptr<UDTemplateArg>>;
  struct UserDefSpecAction;
  struct UserDefTypeAction; /**< 用户自定义类型 */
  struct UserDefFuncAction; /**< 用户自定义函数 */
  using UDSpecList = std::vector<std::shared_ptr<UserDefSpecAction>>;

  /**
   * @brief 用户定义模板实参内容
   */

  struct UDTemplateArg {
    enum UDTA_Kind {
      UDTAK_ta,  /**< 类型实参*/
      UDTAK_nta, /**< 非类型实参*/
      UDTAK_tta, /**< 模板模板实参*/
    } kind;

   protected:
    UDTemplateArg(UDTA_Kind kind) : kind(kind) {}

   public:
    virtual UDTA_Kind getKind() { return kind; }
  };

  struct UDTTypeArg : public UDTemplateArg {
    std::string type;
    UDTTypeArg(std::string type)
        : UDTemplateArg(UDTAK_ta), type(std::move(type)) {}
  };

  struct UDTNonTypeArg : public UDTemplateArg {
    std::string type;
    std::string expr;
    UDTNonTypeArg(std::string type, std::string expr)
        : UDTemplateArg(UDTAK_nta),
          type(std::move(type)),
          expr(std::move(expr)) {}
  };

  struct UDTTempArg : public UDTemplateArg {
    std::string name;
    UDTTempArg(std::string name)
        : UDTemplateArg(UDTAK_tta), name(std::move(name)) {}
  };

  struct UserDefSpecAction {
    TAList targs;
    virtual ~UserDefSpecAction() {}
  };

  struct UserDefTypeAction : public UserDefSpecAction {
    std::string name;
    using UserDefSpecAction::targs;
  };

  struct UserDefFuncAction : public UserDefSpecAction {
    std::string fname; /**< func/mangled name */
    using UserDefSpecAction::targs;
  };

 public:
  /* Unqiue Name generator */
  std::string getUniqueName() const;

  /* UD-Type Parser */
  clang::QualType parseType(const std::string &var_name,
                            const std::string &var_decl);
  clang::QualType parseType(const std::string &type_str);
  clang::QualType parseTemplateDependentType(
      std::string type_str,
      const std::vector<clang::TemplateArgument> &ud_tas = {});
  std::vector<std::string> parseTemplateDependentTypeListStrings(
      const clang::TemplateDecl *temp_decl,
      const std::vector<clang::QualType> type_list,
      const std::vector<clang::TemplateArgument> &ud_tas = {});
  std::vector<clang::QualType> parseTemplateDependentTypeListTypes(
      const clang::TemplateDecl *temp_decl,
      const std::vector<clang::QualType> type_list,
      const std::vector<clang::TemplateArgument> &ud_tas = {});

  clang::QualType parseBasicTypeToReference(clang::QualType type);
  clang::QualType parseBasicTypeToPointer(clang::QualType type);
  clang::QualType parseBasicTypeToArray(clang::QualType type, unsigned length);
  clang::QualType parseFunctionType(
      clang::QualType ret_type, const std::vector<clang::QualType> &parm_types);

  /* UD-Sentence Parser */
  clang::DeclaratorDecl *parseInitlization(std::string var_name,
                                           std::string var_decl);

 public:
  /* UD-Template Parser */
  clang::TemplateArgument parseTemplateArgument(
      const std::shared_ptr<UDParser::UDTemplateArg> &ta);
  clang::TemplateArgument parseTypeTemplateArgument(std::string type);
  clang::TemplateArgument parseNonTypeTemplateArgument(std::string type,
                                                       std::string expr);
  clang::TemplateArgument parseTemplateTemplateArgument(
      std::string temp);  // 按名字符串检索作为模板模板实参的模板类

  /* UD-Template Spec-er */
  clang::QualType specCXXRecordTemplate(
      std::string rd_name,
      const std::vector<std::shared_ptr<UDTemplateArg>> &tas,
      bool mem_spec = false);
  clang::QualType specCXXRecordTemplate(
      std::string rd_name, const std::vector<clang::TemplateArgument> &tas,
      bool mem_spec = false);
  clang::QualType specCXXRecordTemplate(
      const clang::CXXRecordDecl *rd,
      const std::vector<clang::TemplateArgument> &tas, bool mem_spec = false);
  clang::QualType specCXXRecordTemplate(
      const clang::ClassTemplateDecl *rd,
      const std::vector<clang::TemplateArgument> &tas, bool mem_spec = false);

  bool specFunctionTemplate(
      const std::string &fmangled,
      const std::vector<std::shared_ptr<UDTemplateArg>> &tas);
  bool specFunctionTemplate(const std::string &fmangled,
                            const std::vector<clang::TemplateArgument> &tas);
  bool specFunctionTemplate(const clang::FunctionDecl *fd,
                            const std::vector<clang::TemplateArgument> &tas);
  bool specFunctionTemplate(const clang::FunctionTemplateDecl *fd,
                            const std::vector<clang::TemplateArgument> &tas);

 private:
  bool parseCode(const std::string &code);
};

}  // namespace incparser
}  // namespace rocket

#endif  // TYPEGENERATOR_H
